<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/7/13 0013
 * Time: 下午 2:04
 */

namespace common\components\ActionsComponents;
use api\components\LanguageTemplate;

use common\components\DataHelper;

class ListAction extends CommonAction
{
    public $orderBy = 'id DESC';
    public $outBefore = null; //在输出前执行
    public $runBefore = null; //在执行前执行
    public $all = false;
    public $fields = [];
    public $fields_ex = []; // 排除字段
    public $with;
    public $size;
    public $groupBy;
    public $params;
    public $asArray;

    public function run()
    {
        $ctl = $this->controller;

        if ( $this->runBefore instanceof \Closure ) {
            $fun = $this->runBefore;
            try{
                $fun($this->_request);
            }catch(\Exception $e){
                return $ctl->failOut($ctl::RESPONSE_FAILURE, $e->getMessage());
            }
        }

        $model = $this->model;
        $query = $model::find()->where($this->condition)->orderBy($this->orderBy);

        if ( $this->fields_ex ) {
            $instance = new $model();
            $this->fields = array_diff(array_keys($instance::getTableSchema()->columns), $this->fields_ex);
            unset($instance);
        }

        if ( $this->fields ) {
            $query->select($this->fields);
        }

        if ( $this->groupBy ) {
            $query->groupBy($this->groupBy);
        }

        if ( method_exists($model, "createSearchCondition") ) {
            $model::createSearchCondition($query, \Yii::$app->request->get());
        }
        if ( $this->with ) {
            if ( $this->with instanceof \Closure ) {
                $with = $this->with;
                $this->with = $with();
            }
            $this->with && $query->with($this->with);
        }
        if ( $this->all ) {
            $data["items"] = $query->asArray()->all();
        } else {
            if ( $this->asArray ) {
                $query->asArray(true);
            }
            $active = DataHelper::getActiveDataProvider($query, [
                'pagination'=>[
                    'pageSize' => $this->size,
                    'pageParam'=>'page', //page=1
                    'pageSizeParam' => 'size', //size=10
                    'validatePage' => false
                ]
            ]);

            if ( !$this->asArray && $this->with ) {
                $data = $active->getModels();
                $data = $this->newDataByWith($data, $this->with);
                $active->setModels($data);
            }

            try {
                $data = $ctl->serialData($active);#print_r($data);die;
            } catch ( \yii\db\Exception $e ) {
                return $ctl->failOut($ctl::DATA_QUERY_FAIL, LanguageTemplate::tApi(LanguageTemplate::DATA_QUERY_FAIL).$e->getMessage());
            }
            if(empty($data)){
                return $ctl->failOut($ctl::DATA_EMPTY_FAIL, LanguageTemplate::tApi(LanguageTemplate::DATA_EMPTY_FAIL));
            }
        }

        if ( $this->outBefore instanceof \Closure ) {
            $fun = $this->outBefore;
            $fun($data);
        }

        if ( $this->params instanceof \Closure ) {
            $fun = $this->params;
            try{
                $this->params = $fun();
            }catch(\Exception $e){
                return $ctl->failOut($ctl::RESPONSE_FAILURE, $e->getMessage());
            }
        }

        if ( $this->params ) {
            $data["_meta"] = array_merge($data["_meta"], $this->params);
        }
        return $ctl->pullOut($data, false, true);
    }

    private function newDataByWith($data, $with)
    {
        $tmp = [];
        foreach ( $data as $key => $item ) {
            $tmp[$key] = $item->toArray();
            if ( is_array($with) ) {
                foreach ( $with as $withItem ) {
                    if ( $withItem instanceof \Closure ) {
                        continue;
                    }
                    $tmp[$key][$withItem] = $item[$withItem];
                }
            } else {
                $tmp[$key][$with] = $item[$with];
            }
        }
        return $tmp;
    }
}